import { Component } from 'react'
import router from 'umi/router'
import { RouteComponentProps } from 'react-router'
import { ApolloConsumer, Mutation, Query } from 'react-apollo'
import { ApolloClient, gql } from 'apollo-boost'
import { Spin } from 'antd'
import ItemForm from './components/form'
import { Item, ItemCategory, DeepPartial } from './type'

interface Props extends RouteComponentProps<{ id: string }> {}

export default class ItemPage extends Component<Props> {
  key = 'Item'
  path = '/items'

  get id() {
    const { id } = this.props.match.params
    return id.length > 1 ? id : ''
  }

  async componentDidMount() {
    const { client } = await import('../../apollo')
    const categories = await queryCategories(client)
    const del = ({ id }: ItemCategory) => deleteCategory(client, id)
    categories && categories.filter(isEmptyCategory).forEach(del)
  }

  render = () =>
    ((
      {
        location: {
          query: { edit },
        },
      },
      { id, key, path },
    ) => (
      <Query query={QUERY_ITEM} variables={{ id }} skip={!id}>
        {({ loading, data, refetch }) => (
          <Spin spinning={loading && !!id}>
            <Mutation mutation={UPDATE_OR_CREATE_ITEM}>
              {mutate => (
                <Mutation mutation={DELETE_ITEM}>
                  {deletes => (
                    <ApolloConsumer>
                      {client => (
                        <ItemForm
                          data={{ ...data[key], id }}
                          editing={!!edit}
                          onCancel={() => router.replace(path + '/' + id)}
                          onEdit={() =>
                            router.replace(path + '/' + id + '?edit=1')
                          }
                          onDelete={async () => {
                            await deletes({ variables: { id } })
                            const item = data[key]
                            if (item.category && item.category.id) {
                              const category = await queryCategory(
                                client,
                                item.category.id,
                              )
                              if (category && isEmptyCategory(category)) {
                                await deleteCategory(client, category.id)
                              }
                            }
                            router.push(path)
                          }}
                          onSubmit={async data => {
                            console.log(key, data)
                            type V = DeepPartial<Item & { categoryId: string }>
                            let variables: V = data
                            if (data.category && data.category.title) {
                              let category =
                                (await queryCategoryByTitle(
                                  client,
                                  data.category.title,
                                )) ||
                                (await createCategory(client, {
                                  title: data.category.title,
                                }))
                              variables = { ...data, categoryId: category.id }
                            }
                            console.log('variables', variables)
                            const result = await mutate({ variables })
                            const { id } =
                              result && result.data['updateOrCreate' + key]
                            if (id === data.id) await refetch()
                            router.replace(path + '/' + id)
                          }}
                        />
                      )}
                    </ApolloConsumer>
                  )}
                </Mutation>
              )}
            </Mutation>
          </Spin>
        )}
      </Query>
    ))(this.props, this)
}

const isEmptyCategory = (c: ItemCategory) =>
  (c as any)['_itemsMeta']['count'] <= 0

const queryCategories = async (client: ApolloClient<{}>, filter: {} = {}) => {
  const key = 'allItemCategories'
  type R = { [key]: ItemCategory[] }
  const result = await client.query<R>({
    query: QUERY_CATEGORIES,
    variables: { filter },
    fetchPolicy: 'network-only',
  })
  const categories = result && result.data && result.data[key]
  console.log('queried categories', categories, result)
  return categories
}

const queryCategoryByTitle = async (
  client: ApolloClient<{}>,
  title: string,
) => {
  const categories = await queryCategories(client, { title })
  const category = categories && categories.length > 0 && categories[0]
  console.log('queried category by title', category)
  return category
}

const queryCategory = async (client: ApolloClient<{}>, id: string) => {
  const key = 'ItemCategory'
  type R = { [key]: ItemCategory }
  const result = await client.query<R>({
    query: QUERY_CATEGORY,
    variables: { id },
    fetchPolicy: 'network-only',
  })
  const category = result && result.data && result.data[key]
  console.log('queried category', category, result)
  return category
}

const createCategory = async (
  client: ApolloClient<{}>,
  data: Partial<ItemCategory>,
) => {
  const key = 'createItemCategory'
  type R = { [key]: ItemCategory }
  const result = await client.mutate<R>({
    mutation: CREATE_CATEGORY,
    variables: data,
  })
  const category = result && result.data && result.data[key]
  console.log('created category', category, result)
  return category
}

const deleteCategory = async (client: ApolloClient<{}>, id: string) => {
  const key = 'deleteItemCategory'
  type R = { [key]: ItemCategory }
  const result = await client.mutate<R>({
    mutation: DELETE_CATEGORY,
    variables: { id },
  })
  const category = result && result.data && result.data[key]
  console.log('deleted category', category, result)
  return category
}

export const QUERY_ITEM = gql`
  query($id: ID!) {
    Item(id: $id) {
      id
      title
      intro
      price
      category {
        id
        title
      }
      tags
      images
      createdAt
      updatedAt
    }
  }
`

export const UPDATE_OR_CREATE_ITEM = gql`
  mutation(
    $id: ID!
    $title: String!
    $intro: String!
    $price: Int!
    $categoryId: ID
    $tags: [String!]!
    $images: [String!]!
  ) {
    updateOrCreateItem(
      create: {
        title: $title
        intro: $intro
        price: $price
        categoryId: $categoryId
        tags: $tags
        images: $images
      }
      update: {
        id: $id
        title: $title
        intro: $intro
        price: $price
        categoryId: $categoryId
        tags: $tags
        images: $images
      }
    ) {
      id
    }
  }
`

export const DELETE_ITEM = gql`
  mutation($id: ID!) {
    deleteItem(id: $id) {
      id
    }
  }
`

export const QUERY_CATEGORIES = gql`
  query($filter: ItemCategoryFilter) {
    allItemCategories(filter: $filter) {
      id
      _itemsMeta {
        count
      }
    }
  }
`

export const QUERY_CATEGORY = gql`
  query($id: ID!) {
    ItemCategory(id: $id) {
      id
      _itemsMeta {
        count
      }
    }
  }
`

export const CREATE_CATEGORY = gql`
  mutation($title: String!) {
    createItemCategory(title: $title) {
      id
    }
  }
`

export const DELETE_CATEGORY = gql`
  mutation($id: ID!) {
    deleteItemCategory(id: $id) {
      id
    }
  }
`
